package com.dongzili.easyes.common.mybatisplus;

import com.baomidou.mybatisplus.core.conditions.SharedString;
import com.baomidou.mybatisplus.core.conditions.query.Query;
import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;

public class PropertyLambdaWrapper<T>  extends PropertyAbstractLambdaWrapper<T, PropertyLambdaWrapper<T>> implements Query<PropertyLambdaWrapper<T>, T, SFunction<T, ?>> {
        private SharedString sqlSelect;

        public PropertyLambdaWrapper() {
            this((T) null);
        }

        public PropertyLambdaWrapper(T entity) {
            this.sqlSelect = new SharedString();
            super.setEntity(entity);
            super.initNeed();
        }

        public PropertyLambdaWrapper(Class<T> entityClass) {
            this.sqlSelect = new SharedString();
            super.setEntityClass(entityClass);
            super.initNeed();
        }

        PropertyLambdaWrapper(T entity, Class<T> entityClass, SharedString sqlSelect, AtomicInteger paramNameSeq, Map<String, Object> paramNameValuePairs, MergeSegments mergeSegments, SharedString paramAlias, SharedString lastSql, SharedString sqlComment, SharedString sqlFirst) {
            this.sqlSelect = new SharedString();
            super.setEntity(entity);
            super.setEntityClass(entityClass);
            this.paramNameSeq = paramNameSeq;
            this.paramNameValuePairs = paramNameValuePairs;
            this.expression = mergeSegments;
            this.sqlSelect = sqlSelect;
            this.paramAlias = paramAlias;
            this.lastSql = lastSql;
            this.sqlComment = sqlComment;
            this.sqlFirst = sqlFirst;
            this.propertyDbTypeEnum = PropertyDbTypeEnum.ES;
        }
        PropertyLambdaWrapper(PropertyDbTypeEnum propertyDbTypeEnum, T entity, Class<T> entityClass, SharedString sqlSelect, AtomicInteger paramNameSeq, Map<String, Object> paramNameValuePairs, MergeSegments mergeSegments, SharedString paramAlias, SharedString lastSql, SharedString sqlComment, SharedString sqlFirst) {
            this.sqlSelect = new SharedString();
            super.setEntity(entity);
            super.setEntityClass(entityClass);
            this.paramNameSeq = paramNameSeq;
            this.paramNameValuePairs = paramNameValuePairs;
            this.expression = mergeSegments;
            this.sqlSelect = sqlSelect;
            this.paramAlias = paramAlias;
            this.lastSql = lastSql;
            this.sqlComment = sqlComment;
            this.sqlFirst = sqlFirst;
            this.propertyDbTypeEnum = propertyDbTypeEnum;
        }

        public PropertyLambdaWrapper<T> select(boolean condition, List<SFunction<T, ?>> columns) {
            return this.doSelect(condition, columns);
        }

        public PropertyLambdaWrapper<T> select(Class<T> entityClass, Predicate<TableFieldInfo> predicate) {
            if (entityClass == null) {
                entityClass = this.getEntityClass();
            } else {
                this.setEntityClass(entityClass);
            }

            Assert.notNull(entityClass, "entityClass can not be null", new Object[0]);
            this.sqlSelect.setStringValue(TableInfoHelper.getTableInfo(entityClass).chooseSelect(predicate));
            return this.typedThis;
        }

        @SafeVarargs
        public final PropertyLambdaWrapper<T> select(SFunction<T, ?>... columns) {
            return this.doSelect(true, CollectionUtils.toList(columns));
        }

        @SafeVarargs
        public final void select(String aggregation, SFunction<T, ?>... columns) {

            if (CollectionUtils.isNotEmpty(CollectionUtils.toList(columns))) {
                String selectSqlStr = this.columnsToString(false, columns);
                if (StringUtils.hasText(selectSqlStr) && StringUtils.hasText(aggregation)){
                    selectSqlStr = selectSqlStr+","+aggregation;
                }
                this.sqlSelect.setStringValue(selectSqlStr);
            }
        }
        public final void select(List<SFunction<T, ?>> columns, String aggregation) {

            if (CollectionUtils.isNotEmpty(CollectionUtils.toList(columns))) {
                String selectSqlStr = this.columnsToString(false, columns);
                if (StringUtils.hasText(selectSqlStr) && StringUtils.hasText(aggregation)){
                    selectSqlStr = selectSqlStr+","+aggregation;
                }
                this.sqlSelect.setStringValue(selectSqlStr);
            }
        }

        @SafeVarargs
        public final PropertyLambdaWrapper<T> select(boolean condition, SFunction<T, ?>... columns) {
            return this.doSelect(condition, CollectionUtils.toList(columns));
        }

        protected PropertyLambdaWrapper<T> doSelect(boolean condition, List<SFunction<T, ?>> columns) {
            if (condition && CollectionUtils.isNotEmpty(columns)) {
                this.sqlSelect.setStringValue(this.columnsToString(false, columns));
            }

            return this.typedThis;
        }

        public String getSqlSelect() {
            return this.sqlSelect.getStringValue();
        }

        protected PropertyLambdaWrapper<T> instance() {
            return new PropertyLambdaWrapper<>(this.getEntity(), this.getEntityClass(), null, this.paramNameSeq, this.paramNameValuePairs, new MergeSegments(), this.paramAlias, SharedString.emptyString(), SharedString.emptyString(), SharedString.emptyString());
        }

        public void clear() {
            super.clear();
            this.sqlSelect.toNull();
        }
    }